#include	<assert.h>

int last=0;
int acceptor_asked_count=0;
struct timeval mtv;
double avg_latency=0;
//------------------------------------------------------------------------------
int getMicroseconds()
{
	int m;
	gettimeofday(&mtv,NULL);
	m = 1000*mtv.tv_sec+mtv.tv_usec/1000;
	return m;
}
//------------------------------------------------------------------------------
void learner_deliver()
{
	int i,j,k;
	bool flag;
	int gap_length=0;
	gap g;

	for(i = lowestDelivered+1; i < highestDeliverable + 1; i++)
	  {
		  if(data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].received)
			{
				if(!data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].deliver)
				  {
					  if(data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].packet.pack_id == (i+1))
						{
							for(k=0;k<MAX_MSG_COUNT;k++)
								  avg_latency+=getMicroseconds()-data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].packet.msgs[k].microseconds;
							flag=true;

							data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].dec=data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].packet.pack_id;
							data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].deliver=true;
							data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].received=false;
							data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].deliver=false;

							for(k = 0; k < MAX_MSG_COUNT; k++)
								  data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].packet.msgs[k].msg_id=0;

							data[COORDINATOR_ID][ ( i % INTERNAL_BUFFER_SIZE ) ].packet.pack_id=0;
							deliveryCount++;
							rd++;
						}
				  }
			}
		  else{
			g.start = i;
			g.end = i;
			gap_length = 0;
			if(g.start > last){
				for(j = i+1; j < highestDeliverable; j++){
					if(gap_length < MAX_GAP_LENGTH){
						if(data[COORDINATOR_ID][ ( j % INTERNAL_BUFFER_SIZE ) ].received)
			   			  break;
			   			else{ 
			   				g.end=j;
			   				gap_length++;
			   			}
			   		 }
			   	}
			     if(last!=g.end){
			   		last=g.end;
			   		LOST++;
			   		status = send(acceptor_sid,&g,sizeof(gap),MSG_WAITALL);
			   		assert(sttaus >= 0);
			   	}
			}
			break;
		}
	  }
	lowestDelivered=i-1;
}
//------------------------------------------------------------------------------
void recv_new_packet(int sd, short event, void * arg)
{
	int status = -1;
	unsigned int len = sizeof(struct sockaddr);
	int i;
	
	status = recvfrom(sd, new_data, sizeof(inst), MSG_WAITALL, (struct  sockaddr *) ipmAddr, &len);
	assert(status > 0);
	if(status == sizeof(inst))
	  {	 
		  r_tag=true;
		  if(highestDeliverable != new_data->highestDeliverable)
			{	
				highestDeliverable = new_data->highestDeliverable;
				learner_deliver();
			}
		
		  if(data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].packet.pack_id == new_data->packet.pack_id)
				redundant++;
		  else
			{ 
				RECEIVED++;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].received=true;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].deliver=false;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].instance_id=new_data->instance_id;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].packet.pack_id=new_data->packet.pack_id;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].coordinator_id=new_data->coordinator_id;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].dec=new_data->dec;
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].highestDeliverable=-1;
				
				data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].packet.msgs[0].msg_id=new_data->packet.msgs[0].msg_id;
				for(i=0;i<MAX_MSG_COUNT;i++)
					memcpy(&data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].packet.msgs[i],&new_data->packet.msgs[i], sizeof(msg));
			}
	  }
}
//------------------------------------------------------------------------------
void recv_lost_packet(int sd, short event, void *arg){
	
	int status, i;
	inst temp;
	memset(&temp,'\0',sizeof(inst));
	status = recv(sd, &temp, sizeof(inst),MSG_WAITALL);
	assert(status > 0);
	if(status == sizeof(inst)){
	    if((temp.instance_id==(temp.packet.pack_id-1))){
		   acceptor_asked_count++;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].received=true;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].deliver=false;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].instance_id=temp.instance_id;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].packet.pack_id=temp.packet.pack_id;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].coordinator_id=temp.coordinator_id;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].dec=temp.dec;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].highestDeliverable=-1;
	   	   data[temp.coordinator_id][(temp.instance_id % INTERNAL_BUFFER_SIZE)].packet.msgs[0].msg_id=temp.packet.msgs[0].msg_id;
	   	   
	   	   for(i=0;i<MAX_MSG_COUNT;i++)
	   			memcpy(&data[new_data->coordinator_id][(new_data->instance_id % INTERNAL_BUFFER_SIZE)].packet.msgs[i],&temp.packet.msgs[i], sizeof(msg));
	      }
	    else{
	   	   acceptor_asked_count++;
	   	   nr++;
	   	   data[COORDINATOR_ID][ ( (temp.instance_id) % INTERNAL_BUFFER_SIZE ) ].received=true;
	   	   data[COORDINATOR_ID][ ( (temp.instance_id) % INTERNAL_BUFFER_SIZE ) ].deliver=true;
	   }
 	}
}
//------------------------------------------------------------------------------

